home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / listings / v_11_01 / 1101046a < prev    next >
Text File  |  1992-11-07  |  16KB  |  580 lines

  1. #if !defined TSTREAM_H
  2. #define TSTREAM_H
  3.  
  4. #include <iostream.h>    // for base class definitions
  5.  
  6. // class tbuf<>.  Derived publicly from streambuf to 
  7. // allow class ios which contains pointer to streambuf
  8. // access to virtual functions.  tbuf<> implements 
  9. // basic buffering, reading, writing and seeking on
  10. // a stream.  It also provides open, close, attach, 
  11. // and utility functions.
  12. template <class T>
  13. class tbuf : public streambuf {
  14. public:
  15. // openProtection provides a default parameter to the 
  16. // open functions to specify what protection a file 
  17. // will be created with.  You can ignore this if it is
  18. // not necessary
  19. static const int openProtect;
  20. // tbufSize specifies the default buffer size.  It is 
  21. // set to 516 bytes.  
  22. static const int tbufSize;
  23. // Default contructor.  Make a buffer without a 
  24. // stream attached.  mode has a dual meaning, if it 
  25. // is zero it means that any operation is allowable, 
  26. // and the stream should not be deleted when closing.  
  27.     tbuf()
  28.         : stream(0), mode(0), opened(0)
  29.     {
  30.         makbuf();
  31.     }
  32. // create buffer and attach to t.  t is assumed to be
  33. // already opened in read/write mode.  t will not be
  34. // deleted or closed when closing this buffer
  35.     tbuf(T &t)    
  36.         : stream(&t), mode(0), opened(1)
  37.     {
  38.         makbuf();
  39.     }
  40. // create buffer from parameters, and attach to t.
  41.     tbuf(T &t, char* b, int l)    
  42.         : stream(&t), mode(0), opened(1)
  43.     {
  44.         setbuf(b, l);
  45.     }
  46. // destroy buffer.  If mode is not zero, t will be 
  47. // closed and deleted.  Otherwise just flush the 
  48. // output buffer.
  49.     ~tbuf()
  50.     {                
  51.         if(mode)
  52.             close();
  53.         else
  54.             overflow(EOF);
  55.     }
  56. // return open status
  57.     int is_open() const 
  58.     { 
  59.         return opened; 
  60.     }
  61. // return reference to stream
  62.     T &fd() const 
  63.     { 
  64.         return *stream; 
  65.     }
  66. // open stream.  mode must not be zero.  stream will 
  67. // be closed and deleted when closing buffer.
  68.     tbuf *open(const char *name, int mode, 
  69.                        int prot = tbuf::openProtect);
  70. // close buffer and optionally delete stream.
  71.     tbuf *close();              
  72. // attach stream to buffer.  Stream is assumed to
  73. // be opened in read/write mode.
  74.     tbuf *attach(T &);  
  75. // write buffer to stream and reset pointers.
  76.     virtual int overflow(int = EOF);
  77. // read data into buffer and reset pointers.
  78.     virtual int underflow();
  79. // sync input and output.
  80.     virtual int sync();    
  81. // seek to offset and flush output buffers.
  82.     virtual long seekoff(long, ios::seek_dir, int);
  83. // set buffer.  For unbuffered i/o set char * to 0.
  84.     virtual streambuf *setbuf(char  *, int);
  85. protected:
  86.     int putBackSize() 
  87.     { 
  88.         return (blen() > 8) ? 4 : 1; 
  89.     }    
  90.     void resetpg(int end = 0);
  91.     void makbuf() 
  92.     { 
  93.         setbuf(new char[tbufSize], tbufSize); 
  94.     }
  95.     int unbuffered() 
  96.     { 
  97.         return streambuf::unbuffered() | !base(); 
  98.     }
  99.     T     *stream;        
  100.     int   mode;       
  101.     short opened; 
  102.     char  lookAhead[2];      
  103. };
  104.  
  105. template <class T> 
  106. const int tbuf<T>::tbufSize = 516;
  107. template <class T> 
  108. const int tbuf<T>::openProtect = 0;
  109.  
  110. // Attach an open stream to this buffer.  When this 
  111. // buffer is closed don't try to close stream.  If 
  112. // not yet buffered, try to create a buffer.  Reset 
  113. // the put and get pointers.  Return 0 on error, or 
  114. // this if OK.
  115. template <class T>
  116. tbuf<T>* tbuf<T>::attach(T &t)
  117. {
  118.     if(opened)        // if already opened, return 0
  119.         return 0;
  120.     stream = &t;    // attach stream.
  121.     opened = 1;     // set to opened.
  122.     mode = 0;       // buffer doesn't own stream.
  123.     if(!base())        // if no buffer yet...
  124.         makbuf();    // try to make one.
  125.     else
  126.         resetpg();    // reset put and get pointers.
  127.     return this;
  128. }
  129.  
  130. // Close buffer, and optionally stream attached to it.
  131. // Flush buffer if data inside.  Return 0 on error or
  132. // this if OK.
  133. template <class T>
  134. tbuf<T>* tbuf<T>::close()
  135. {
  136.     if(!*stream)    // if stream closed, 
  137.         opened = 0;    // set opened off.
  138.     if(!opened)        // if not on return 0.
  139.         return 0;       
  140.     int ret = 0;       
  141.     if(out_waiting())    // if output in buffer.
  142.             // flush output buffer.
  143.         ret = (overflow(EOF) == EOF) ? 1 : 0;    
  144.     if(mode)        // if mode is 0, don't
  145.         delete stream;    // close or delete stream.
  146.     opened = 0;        // set opened off.
  147.     return ret ? 0 : this;
  148. }
  149.  
  150. // Write data from buffer to stream.  This function 
  151. // is called when the buffer is full and we need to 
  152. // output more characters.  The parameter c is the 
  153. // character that caused the overflow.  If the 
  154. // stream is buffered, it will be placed in the 
  155. // buffer, otherwise it is written to the stream.
  156. // If input char is EOF, don't write, just flush.  
  157. // Returns EOF on error, or 1 on success.  
  158. template <class T>
  159. int tbuf<T>::overflow(int c)
  160. {
  161.     if(!opened ||     // check to see if stream
  162.         mode == 0 ||     // is on and mode is out.
  163.         !(mode&ios::out))
  164.         return EOF;            
  165.     if(unbuffered())
  166.     {
  167.         if(c != EOF)
  168.         {        // if unbuffered, 
  169.             char b = c;    // write single char
  170.             if(stream->write(&b, 1) != 1)
  171.                 return EOF;
  172.         }
  173.     }
  174.     else        // else if buffered.
  175.     {
  176.         if(sync() != 0)    // sync input and output 
  177.             return EOF;    // when writing
  178.         resetpg(1);    // reset the put/get pointers
  179.         if(c != EOF)
  180.         {
  181.             sputc(c);    // add c to the buffer
  182.             gbump(1);   // move the get pointer
  183.         }
  184.     }
  185.     return 1;        // return OK
  186. }
  187.  
  188. // Open stream.  If mode ios::ate (at end) is on, 
  189. // seek to end
  190. template <class T>
  191. tbuf<T>* tbuf<T>::open(const char* n, int m, int p)
  192. {
  193.     if(opened || !m)    // if already on, or no mode,
  194.         return 0;    // return error.
  195.     stream = new T;    // make new stream pointer.
  196.     stream->open(n, m, p);// open stream.
  197.     if(!*stream)    // if stream not open,
  198.         return 0;    // return error.
  199.     opened = 1;        // set to on.
  200.     mode = m;        // remeber mode.
  201.     if((mode & ios::ate) &&    
  202.            stream->seek(0L, ios::end) == EOF)
  203.         return 0;    // seek to end if ios::ate. 
  204.     resetpg();        // reset put/get pointers.
  205.     return this;    // return OK.
  206. }
  207.  
  208. // Set the buffer, reset the put/get pointers.  
  209. // Return 0 on error, this if OK.
  210. template <class T>
  211. streambuf* tbuf<T>::setbuf(char* b, int l)
  212. {
  213.     if(!b)        // turn off buffering.
  214.     {
  215.         streambuf::unbuffered(1);
  216.         return this;
  217.     }
  218.     if(opened && base())// check if stream is opened,
  219.         return 0;       // , and no buffer yet.
  220.     setb(b, b+l, 0);    // set buffer pointers.
  221.     resetpg();        // reset put/get pointers.
  222.     return this;    // return OK.
  223. }
  224.  
  225. // Seek to offset.  dir indicates the relativity of 
  226. // the offset, ethier from beginning, current postion,
  227. // or end (ios::beg, ios::cur, ios::end).  
  228. // First make sure there's nothing in the buffer.
  229. template <class T>
  230. long tbuf<T>::seekoff(long off, ios::seek_dir dir, 
  231.                              int /* mode ignored */)
  232. {
  233.     long loff = off;
  234.     int count = out_waiting();    // flush output first.
  235.     if(count)
  236.     {       
  237.         if(stream->write(pbase(), count) != count)
  238.             return EOF;
  239.     }
  240.     else if(dir == ios::cur && // if relative seek,
  241.             (count = in_avail()) != 0)
  242.         loff -= count;        // discount input.
  243.     resetpg();            // reset pointers.
  244.     return stream->seek(loff, dir);
  245. }
  246.  
  247. // sync input and output buffer pointers.  If output
  248. // is waiting, write it, if input is waiting, 
  249. // back up to read it again
  250. template <class T>
  251. int tbuf<T>::sync()
  252. {
  253.     if (!opened)        // check if opened.
  254.         return EOF;
  255.     int count = out_waiting();    // check for output,
  256.     if(count)            // in buffer.
  257.     {
  258.         if(stream->write(pbase(), count) != count)
  259.             return EOF;        // write output. 
  260.         resetpg(1);
  261.     }
  262.     else if(in_avail())        // check for input
  263.     {                // in buffer
  264.         long pos = stream->seek(long(-in_avail()), 
  265.